package cae.gui;
/***
 * Windows Tray Icon
 * -----------------
 *
 * Written by Jan Struyf
 *
 *  jan.struyf@cs.kuleuven.ac.be
 *  http://jeans.studentenweb.org/java/trayicon/trayicon.html
 *
 * Please mail me if you
 *	- 've found bugs
 *	- like this program
 *	- don't like a particular feature
 *	- would like something to be modified
 *
 * I always give it my best shot to make a program useful and solid, but
 * remeber that there is absolutely no warranty for using this program as
 * stated in the following terms:
 *
 * THERE IS NO WARRANTY FOR THIS PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
 * LAW. THE COPYRIGHT HOLDER AND/OR OTHER PARTIES WHO MAY HAVE MODIFIED THE
 * PROGRAM, PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 * TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 * PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 * REPAIR OR CORRECTION.
 *
 * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL ANY COPYRIGHT HOLDER,
 * OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM,
 * BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
 * PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
 * INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
 * PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
 * PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * May the Force be with you... Just compile it & use it!
 */


import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;

import org.apache.log4j.Logger;

import cae.gui.chat.CaeChatDialog;
import cae.gui.destination.CaeAddDestinationDialog;
import cae.gui.destination.CaeAddGroupDialog;
import cae.gui.destination.CaeDeleteDestinationDialog;
import cae.gui.destination.CaeDeleteGroupDialog;
import cae.gui.file.CaeSendFileDialog;
import cae.gui.history.CaeHistoryDialog;
import cae.gui.msg.CaeSendDialog;
import cae.gui.msg.CaeSendGroupDialog;
import cae.gui.util.CaeImage;
import cae.gui.util.CaePopupUtil;
import cae.logic.CaeMessage;
import cae.logic.CaeMessagePublisher;
import cae.logic.chat.CaeChatManager;
import cae.logic.destination.CaeDestination;
import cae.logic.destination.CaeDestinatiosManager;
import cae.logic.destination.CaeGroup;
import cae.logic.destination.CaeGroupManager;
import cae.logic.util.CaeClipConfiguration;

public class CaeClip implements CaeMessagePublisher, Observer
{

	private TrayIcon icon;
	private CaeDestination lastDestination;
	private boolean showAutoMessages;
	private Map<CaeDestination, JMenuItem> enviarItems;
	private static Logger logger = Logger.getLogger(CaeClip.class);
	private AudioClip popupSound;
	private CaeChatManager chatLogic; // TODO singleton 
	private static CaeChatDialog chatDialog;
	
	private JPopupMenu contextMenu;
	
	public CaeClip()
	{
		try 
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} 
		catch (Exception ex) 
		{
			// IGNORE
		}
		
		try {
			String appName = "CaeClip";
			SystemTray tray = SystemTray.getSystemTray();

			String iconPath = CaeClipConfiguration.getInstance().getSProp(CaeClipConfiguration.ICON_FILE);
			Image defaultIcon = Toolkit.getDefaultToolkit().getImage(iconPath);
			icon = new TrayIcon(defaultIcon, appName);
			
			chatLogic = new CaeChatManager();
			new Thread(chatLogic).start();
			chatLogic.addObserver(this);
			
			tray.add(icon);
			makePopups();
			
			//icon.addBalloonListener(new BalloonListener()); TODO
			icon.addMouseListener(new MouseListener()
			{
				public void mouseClicked(MouseEvent arg0) {
					
				}
				public void mouseEntered(MouseEvent arg0) {}
				public void mouseExited(MouseEvent arg0) {}
				public void mousePressed(MouseEvent arg0) {}
				public void mouseReleased(MouseEvent e) 
				{
					if(e.getModifiers() == MouseEvent.BUTTON1_MASK && e.getClickCount() == 2)
					{
						if( chatDialog == null || !chatDialog.isVisible() ) 
						chatDialog = new CaeChatDialog(null, chatLogic, icon);
						chatDialog.setVisible(true);
					}
					else if (e.isPopupTrigger()) {
						contextMenu.setLocation(e.getX(), e.getY());
						contextMenu.setInvoker(contextMenu);
						contextMenu.setVisible(true);
			        }
					
				}
			});
			
			showAutoMessages = CaeClipConfiguration.getInstance().getIProp(CaeClipConfiguration.AUTO_MESSAGES) != 0;
			
			String popupSoundPath = CaeClipConfiguration.getInstance().getSProp(CaeClipConfiguration.POPUP_SOUND);
			popupSound = Applet.newAudioClip(new File(popupSoundPath).toURI().toURL());
			
			new Thread(new CaeDestinationTester()).start();
		} 
		catch (Exception e) 
		{
			logger.fatal("No se ha podido iniciar la aplicacion ", e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	public void makePopups()
	{

		enviarItems = new HashMap<CaeDestination, JMenuItem>();

		// Make new popup menu
		contextMenu = new JPopupMenu();
		
		JMenuItem item = new JMenuItem("Chat...");
		item.addActionListener(new ChatListener());
		contextMenu.add(item);

		contextMenu.addSeparator();
		
		// CREO UN ITEM POR DESTINATION
		JMenu enviar = new JMenu("Popup individual");
		List<CaeDestination> dests = CaeDestinatiosManager.getInstance().getDestinations();
		for(CaeDestination dest : dests)
		{
			JMenuItem subitem = new JMenuItem("Enviar a " + dest.getAlias());
			subitem.addActionListener(new SendMessageListener(dest));
			enviar.add(subitem);
			enviarItems.put(dest, subitem);
		}
		contextMenu.add(enviar);
		
		contextMenu.addSeparator();
		
		// CREO UN ITEM POR GROUP
		JMenu grupo = new JMenu("Popup grupal");
		List<CaeGroup> groups = CaeGroupManager.getInstance().getGroups();
		for(CaeGroup gr : groups)
		{
			item = new JMenuItem("Enviar a " + gr.getNick());
			item.addActionListener(new SendMessageGroupListener(gr));
			grupo.add(item);
		}
		contextMenu.add(grupo);

		contextMenu.addSeparator();
		
		item = new JMenuItem("Historial...");
		item.addActionListener(new HistoryListener());
		contextMenu.add(item);
	
		contextMenu.addSeparator();
		
		// CONTACTOS
		JMenu contactos = new JMenu("Edicion de contactos");
		item = new JMenuItem("Agregar Destinatario...");
		item.addActionListener(new AddDestListener());
		contactos.add(item);
		
		item = new JMenuItem("Agregar Grupo...");
		item.addActionListener(new AddGroupListener());
		contactos.add(item);
	
		contactos.addSeparator();
		
		item = new JMenuItem("Eliminar Destinatario...");
		item.addActionListener(new DeleteDestListener());
		contactos.add(item);
		
		item = new JMenuItem("Eliminar Grupo...");
		item.addActionListener(new DeleteGroupListener());
		contactos.add(item);
		contextMenu.add(contactos);
	
		contextMenu.addSeparator();
		
		// ARCHIVOS
		JMenu enviarArchivos = new JMenu("Enviar archivos");
		item = new JMenuItem("Enviar Archivo...");
		item.addActionListener(new SendFileListener());
		enviarArchivos.add(item);
		
		item = new JMenuItem("Archivos recibidos");
		item.addActionListener(new OpenDownloadListener());
		enviarArchivos.add(item);
		contextMenu.add(enviarArchivos);
		
		contextMenu.addSeparator();
		
		item = new JMenuItem("Salir");
		item.addActionListener(new ExitListener());
		contextMenu.add(item);

	}	
	
	public void publishMessage(CaeMessage message, int duracion)
	{

		int soundE = CaeClipConfiguration.getInstance().getIProp(CaeClipConfiguration.SOUND_ENABLED);
		if( soundE != 0)
		{
		    popupSound.play();
		}
		CaeDestination dest = CaeDestinatiosManager.getInstance().getDestination(message.getFrom());
		lastDestination = dest;
		
		if(dest != null)
		{
			//icon.displayMessage(, , TrayIcon.MessageType.INFO);
			new CaePopupUtil(null, "Mensaje de " + dest.getAlias(), message.getText()).showNow();
		}
		else
		{
			icon.displayMessage(message.getText(), "Mensaje de " + message.getFrom(), TrayIcon.MessageType.INFO);
		}
	}
	
	public class ExitListener implements ActionListener 
	{
		public void actionPerformed(ActionEvent evt) 
		{
			SystemTray tray = SystemTray.getSystemTray();
			tray.remove(icon);
			System.exit(0);
		}
	}
	
	public class HistoryListener implements ActionListener 
	{
		public void actionPerformed(ActionEvent evt) {
			new CaeHistoryDialog(null);
		}
	}
	
	public class AutoMessagesListener implements ActionListener 
	{
		public void actionPerformed(ActionEvent evt) {
			showAutoMessages = !showAutoMessages;
		}
	}
	
	/*public class BalloonListener implements TrayBalloonListener
	{
		public void balloonChanged(TrayBalloonEvent arg0) {
			if( arg0.getMask() == TrayBalloonEvent.CLICK && lastDestination != null)
			{
				new CaeSendDialog(null, lastDestination);
			}
		}
	} TODO ICON*/
	
	public class AddDestListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) {
			new CaeAddDestinationDialog(null, true);
			makePopups();
		}
	}
	
	public class DeleteDestListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) {
			new CaeDeleteDestinationDialog(null, true);
			makePopups();
		}
	}
	
	public class AddGroupListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) {
			new CaeAddGroupDialog(null, true);
			makePopups();
		}
	}
	
	public class DeleteGroupListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) {
			new CaeDeleteGroupDialog(null, true);
			makePopups();
		}
	}
	
	public class SendFileListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) {
			new CaeSendFileDialog(null, true);
			makePopups();
		}
	}
	
	public class ChatListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt)
		{
			if( chatDialog == null || !chatDialog.isVisible() )
			{
				chatDialog = new CaeChatDialog(null, chatLogic, icon);
				chatDialog.setVisible(true);
			}
		}
	}
	
	public class OpenDownloadListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt) {
			
			String s = CaeClipConfiguration.getInstance().getSProp(CaeClipConfiguration.FILE_DOWNLOAD_PATH).replaceAll("/", "\\\\");
			try {
				Runtime.getRuntime().exec("explorer.exe"+" \""+s+"\"");
			} catch (IOException e) {
				logger.error("No se pudo ejecutar el explorador en el path: " + s, e);
			}
		}
	}

	public boolean isShowAutoMessages() {
		return showAutoMessages;
	}
	
	public class SendMessageListener implements ActionListener
	{
		private CaeDestination dest;
		
		public SendMessageListener(CaeDestination dest)
		{
			this.dest = dest;
		}
		
		public void actionPerformed(ActionEvent evt) {
			new CaeSendDialog(null, dest);
		}
	}
	
	public class SendMessageGroupListener implements ActionListener
	{
		private CaeGroup group;
		
		public SendMessageGroupListener(CaeGroup group)
		{
			this.group = group;
		}
		
		public void actionPerformed(ActionEvent evt) {
			new CaeSendGroupDialog(null, group);
		}
	}
	
	private class CaeDestinationTester implements Runnable
	{
		public void run()
		{
			while(true)
			{
				try
				{
					if(enviarItems != null)
					{
						Set<CaeDestination> dests = enviarItems.keySet();
						for (CaeDestination destination : dests)
						{
							JMenuItem item = enviarItems.get(destination);
							new Thread(new CaeDestinationSingleTester(destination, item)).start();
						}
					}
				}
				catch(Exception e)
				{
					logger.error("Error al intentar testear destinations ",e);
				}
				
				try {
					Thread.sleep(CaeClipConfiguration.getInstance().getIProp(CaeClipConfiguration.TEME_BATWEEN_DESTINATION_TEST));
				} catch (InterruptedException e) {}
			}
		}
		
		private class CaeDestinationSingleTester implements Runnable
		{
			private CaeDestination destination;
			private JMenuItem item;
			
			private CaeDestinationSingleTester(CaeDestination destination, JMenuItem item)
			{
				this.destination = destination;
				this.item = item;
			}
			
			public void run() {
				try {
					Socket s = new Socket();
					s.connect(new InetSocketAddress(destination.getMachine()[0], destination.getPort()));
				} catch (IOException e) {
					item.setEnabled(false);
					return;
				}
				item.setEnabled(true);
			}
			
		}
	}

	public void update(Observable arg0, Object arg1)
	{
		if( chatDialog == null || !chatDialog.isActive())
		{
			CaeImage.setIcon(icon, CaeImage.MESSAGE);
		}
	}
}